﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Resolve.Contracts;
using Resolve.FlagInfo;
using Resolve.Web;

namespace Resolve.Core
{
    public class HtmlGeneraterFromFile : IHtmlGenerater
    {
        /// <summary>
        /// 代码标志
        /// </summary>
        public FlagCodeInFile FlagCodeInFile { private get; set; }

        /// <summary>
        /// 内存流
        /// </summary>
        private MemoryStream _memoryStream;

        /// <summary>
        /// 文件流
        /// </summary>
        private Stream _streamFile;

        /// <summary>
        /// 初始化
        /// </summary>
        private void InitStream()
        {
            if (_streamFile != null)
            {
                _streamFile.Close();
            }
            _streamFile = File.Open(FlagCodeInFile.Source, FileMode.Open, FileAccess.Read, FileShare.Read);
            if (_memoryStream != null)
            {
                _memoryStream.Close();
            }
            _memoryStream = new MemoryStream();
        }

        /// <summary>
        /// 替换标志，生成Html代码
        /// </summary>
        /// <returns></returns>
        public string Generate()
        {
            InitStream();
            try
            {
                if (FlagCodeInFile == null || FlagCodeInFile.LsCode == null || FlagCodeInFile.LsCode.Count == 0)
                {
                    int iLength;
                    do
                    {
                        byte[] bTemp = new byte[5120];
                        iLength = _streamFile.Read(bTemp, 0, bTemp.Length);
                        _memoryStream.Write(bTemp, 0, iLength);
                    } while (iLength == 5120);
                }
                else
                {
                    object compileObject = FlagCodeInFile.CompileObject;
                    if (compileObject == null)
                    {
                        NoLayout(ref compileObject);
                    }
                    else
                    {
                        ViewPageBase viewPageBase = (ViewPageBase)compileObject;
                        if (string.IsNullOrEmpty(viewPageBase.Layout))
                        {
                            NoLayout(ref compileObject);
                        }
                        else
                        {
                            HaveLayout(ref compileObject);
                        }
                    }

                }
                byte[] data = _memoryStream.ToArray();
                Dispose();
                string s;
                if (FlagCodeInFile != null && FlagCodeInFile.Source != null)
                {
                    Encoding encoding = Encoding.Default;
                    if (FlagCodeInFile.EncodingStyle.Equals(EncodingStyle.Default))
                    {
                        encoding = Encoding.Default;
                    }
                    else if (FlagCodeInFile.EncodingStyle.Equals(EncodingStyle.Utf8))
                    {
                        encoding = Encoding.UTF8;
                    }
                    else if (FlagCodeInFile.EncodingStyle.Equals(EncodingStyle.BigEndianUnicode))
                    {
                        encoding = Encoding.BigEndianUnicode;
                    }
                    else if (FlagCodeInFile.EncodingStyle.Equals(EncodingStyle.Unicode))
                    {
                        encoding = Encoding.Unicode;
                    }
                    else if (FlagCodeInFile.EncodingStyle.Equals(EncodingStyle.Gb2312))
                    {
                        encoding = Encoding.GetEncoding("GB2312");
                    }
                    s = encoding.GetString(data);
                }
                else
                {
                    s = Encoding.Default.GetString(data);
                }

                return s;
            }
            catch (Exception ex)
            {
                Dispose();
                throw new Exception(ex.Message);
            }
        }

        private void NoLayout(ref object compileObject)
        {
            Type compileType = null;
            if (compileObject != null)
            {
                compileType = FlagCodeInFile.CompileObject.GetType();
            }
            List<FlagCode> lsCode = FlagCodeInFile.LsCode;
            int iPosition = 0;
            _streamFile.Seek(3, SeekOrigin.Begin);
            for (int i = 0; i < lsCode.Count; i++)
            {
                byte[] bTemp = new byte[lsCode[i].Start - iPosition];
                if (bTemp.Length != 0)
                {
                    _streamFile.Read(bTemp, 0, bTemp.Length);
                    _memoryStream.Write(bTemp, 0, bTemp.Length);
                }
                string htmlCode = string.Empty;
                switch (lsCode[i].FlagStyle)
                {
                    case FlagStyle.Statement:
                    case FlagStyle.Using:
                    case FlagStyle.Comment:
                    case FlagStyle.Layout:
                        break;
                    case FlagStyle.Property:
                        {
                            if (compileType == null) continue;
                            MethodInfo m = compileType.GetMethod(ResolveConfig.PropertyCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObject, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.Func:
                        //case FlagStyle.PlaceHolder:
                        {
                            if (compileType == null) continue;
                            MethodInfo m = compileType.GetMethod(ResolveConfig.FuncCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObject, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.Body:
                        {
                            if (compileType == null) continue;
                            MethodInfo m = compileType.GetMethod(ResolveConfig.BodyCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObject, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.FlagEscape:
                        {
                            htmlCode = lsCode[i].Code.Remove(0, 1);
                        }
                        break;
                }
                byte[] bb = Encoding.UTF8.GetBytes(htmlCode);
                _memoryStream.Write(bb, 0, bb.Length);
                iPosition = lsCode[i].End + 1;
                _streamFile.Seek(iPosition + 3, SeekOrigin.Begin);
                if ((i + 1) != lsCode.Count) continue;
                bTemp = new byte[1024];
                int iLength;
                do
                {
                    iLength = _streamFile.Read(bTemp, 0, bTemp.Length);
                    _memoryStream.Write(bTemp, 0, iLength);
                } while (iLength == 1024);
            }
        }

        private void HaveLayout(ref object compileObject)
        {
            //Layout
            ViewPageBase viewPageBase = (ViewPageBase)compileObject;
            FlagCodeInFile = viewPageBase.LayoutFlagCodeInFile;
            object compileObjectLayout = viewPageBase.LayoutFlagCodeInFile.CompileObject;
            Type compileTypeLayout = null;

            //Child
            Type compileType = compileObject.GetType();

            InitStream();

            if (compileObjectLayout != null)
            {
                compileTypeLayout = FlagCodeInFile.CompileObject.GetType();
            }
            List<FlagCode> lsCode = FlagCodeInFile.LsCode;
            int iPosition = 0;
            _streamFile.Seek(3, SeekOrigin.Begin);
            for (int i = 0; i < lsCode.Count; i++)
            {
                byte[] bTemp = new byte[lsCode[i].Start - iPosition];
                if (bTemp.Length != 0)
                {
                    _streamFile.Read(bTemp, 0, bTemp.Length);
                    _memoryStream.Write(bTemp, 0, bTemp.Length);
                }
                string htmlCode = string.Empty;
                switch (lsCode[i].FlagStyle)
                {
                    case FlagStyle.Statement:
                    case FlagStyle.Using:
                    case FlagStyle.Comment:
                    case FlagStyle.Layout:
                        break;
                    case FlagStyle.Property:
                        {
                            if (compileTypeLayout == null) continue;
                            MethodInfo m = compileTypeLayout.GetMethod(ResolveConfig.PropertyCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObjectLayout, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.Func:
                        {
                            if (compileTypeLayout == null) continue;
                            MethodInfo m = compileTypeLayout.GetMethod(ResolveConfig.FuncCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObjectLayout, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.PlaceHolder:
                        {
                            string sTemp = lsCode[i].Code;
                            int index1 = sTemp.IndexOf("\"", StringComparison.Ordinal);
                            int index2 = sTemp.LastIndexOf("\"", StringComparison.Ordinal);
                            sTemp = sTemp.Substring(index1 + 1, index2 - index1 - 1);
                            MethodInfo m = compileType.GetMethod(ResolveConfig.PlaceContentName + sTemp);
                            if (m != null)
                            {
                                Func<string> action =
                                    (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObject, m);
                                htmlCode = action();
                            }
                        }
                        break;
                    case FlagStyle.Body:
                        {
                            if (compileTypeLayout == null) continue;
                            MethodInfo m = compileTypeLayout.GetMethod(ResolveConfig.BodyCodeName + i);
                            Func<string> action = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), compileObjectLayout, m);
                            htmlCode = action();
                        }
                        break;
                    case FlagStyle.FlagEscape:
                        {
                            htmlCode = lsCode[i].Code.Remove(0, 1);
                        }
                        break;
                }
                byte[] bb = Encoding.UTF8.GetBytes(htmlCode);
                _memoryStream.Write(bb, 0, bb.Length);
                iPosition = lsCode[i].End + 1;
                _streamFile.Seek(iPosition + 3, SeekOrigin.Begin);
                if ((i + 1) != lsCode.Count) continue;
                bTemp = new byte[1024];
                int iLength;
                do
                {
                    iLength = _streamFile.Read(bTemp, 0, bTemp.Length);
                    _memoryStream.Write(bTemp, 0, iLength);
                } while (iLength == 1024);
            }
        }



        /// <summary>
        /// 关闭资源
        /// </summary>
        private void Dispose()
        {
            if (_streamFile != null)
            {
                _streamFile.Close();
            }
            if (_memoryStream != null)
            {
                _memoryStream.Close();
            }
        }
    }

}
